/**
 *  学习目标：Todos 案例 
 *  需求1：✅渲染任务列表
    步骤：
      1. 在App组件中声明state = {list: [{}]}, 设计数据格式
      2. 父传子技术，将list传给Main
      3. Main组件通过map，生成多个li，填入对应内容

    需求2: ✅更新一条数据-设置选中状态、处理样式
    步骤：
      1. App组件中定义一个修改数据的方法：handleUpdate，给子组件用
      2. 在 Main组件中，给多选按钮绑定一个onChange事件，通过 子传父技术 调用App中定义的方法
      3. 在handleUpdate，根据id，和checked属性，来调用this.setState({})
      4. 通过给class设置表达式，来模拟动态class

    需求3: ✅删除一条数据
    步骤：
      1. App中定义一个删除方法，handleDelete，给子组件使用
      2. 在Main中找到删除按钮，绑定onClick事件，调用handleDelete
      3. 删除的逻辑：通过id删除一条数据即可

    需求4: ✅Footer组件，点谁谁有边框
    步骤：
      1. 在App中state声明一个type，（状态提升）
      2. 通过父传子，将type传给Footer
      3. 在Footer中动态添加class
      4. 给按钮绑定onClick事件，通过子传父技术，修改App中的type


    需求5：✅Footer组件，点击切换显示数据
    步骤
      1. 在render函数中，根据list与type的值，定义showList变量， （类似Vue中的计算属性）
      2. 将showList传给Main组件的list属性

    需求6：✅ 清除已完成任务
    步骤
      1. App组件中定义一个方法: handleClear，清除已完成的任务
      2. 在Footer中给清除按钮，绑定一个onClick事件，通过子传父调用handleClear
      3. handleClear中编写清除的逻辑：this.setState()

      
    需求7: ✅ 统计剩余未完成任务
    步骤：
      1. 在App的render方法中，定义一个变量count，用来统计未完成的数量
      2. 通过父传子，传count给Footer组件
      3. Footer显示出props.count
    注意：💥在render方法中，通过state计算而来的变量，（类似Vue中的计算属性）

         
    需求8: ✅新增任务功能 - 完成新增功能
    注意：
      1. 按回车才新增数据
      2. 按esc，清除输入框内容
      3. 新增后清除输入框内容
      4. 如果数据为空，提示用户，且不添加数据
    步骤：
      1. Header声明一个state.task，
      2. Header成为受控组价：state.task绑定value，onChange监听value变化，setState更新task
      3. 使用onKeyUp监听回车事件，
      4. 通过子传父新增数据到list中
      细节完善
      1. 按esc，清除输入框内容
      2. 新增后，清除输入框内容
      3. 如果数据为空，提示用户，且不添加数据

    需求9：✅数据缓存功能
    需求10： 全选功能-小选影响全选
    需求11：✅ 全选功能-全选影响小选

    
   
 */
import React from 'react';
import './styles/base.css';
import './styles/index.css';

export default class App extends React.Component {
  // 9.1 componentDidUpdate 监听state中list 和type变化，拿到更新后的值
  componentDidUpdate(prevProps, prevState) {
    // 9.2 存入localStore中
    localStorage.setItem('list', JSON.stringify(this.state.list));
    localStorage.setItem('type', this.state.type);
  }

  //  1. 在App组件中声明state = {list: [{}]},   设计数据格式
  state = {
    // 9.3 取出localStore中的list 和 type
    list: JSON.parse(localStorage.getItem('list')) || [],
    //    4.1. 在App中声明一个type，（状态提升）

    type: localStorage.getItem('type'),
  };
  // 2.1 App组件中定义一个修改数据的方法：handleUpdate，给子组件用
  handleUpdate = (e, id) => {
    // 2.3. 在handleUpdate，根据id，和checked属性，来调用this.setState({})
    this.setState({
      // 遍历数组，根据id更新对应的数据，并返回整个数组
      list: this.state.list.map((item) => {
        // 如果id 与item.id 相等，就把item.isDone改为e.target.checked
        if (item.id === id) {
          return {
            ...item,
            // 注意：相同的键，后者会覆盖前者
            isDone: e.target.checked,
          };
        }
        return item;
      }),
    });
  };

  // 3.1. App中定义一个删除方法，handleDelete，给子组件使用
  handleDelete = (id) => {
    // 3.3 删除的逻辑：通过id删除一条数据即可
    const newList = this.state.list.filter((item) => {
      return item.id !== id;
    });
    this.setState({ list: newList });
  };

  handleToggle = (type) => {
    this.setState({ type });
  };

  //    1. App组件中定义一个方法: handleClear，清除已完成的任务
  handleClear = () => {
    //   3. handleClear中编写清除的逻辑：this.setState()
    const list = this.state.list.filter((item) => !item.isDone);
    this.setState({ list });
  };

  handleAdd = (task) => {
    // 4.通过子传父新增数据到list中
    // 复制一份list，通过push方法新增一条记录
    const list = [{ id: Date.now(), task, isDone: false }, ...this.state.list];

    this.setState({ list });
  };
  //    11.2 通过子传父，将checked属性传给App
  handleCheckAll = (checked) => {
    // 11.3 App通过map方法修改list中每一项的isDone
    const list = this.state.list.map((item) => ({ ...item, isDone: checked }));
    this.setState({ list });
  };

  render() {
    const { list, type } = this.state;

    // 5.1 在render函数中，根据list与type的值，定义showList变量
    // state中的list和type变化时，render函数会重新执行，下方整个showList的计算结果，会每次都更新。
    //✌ render中根据state的值，计算得到的新的值，可以理解为Vue中的计算属性
    const showList = this.state.list.filter((item) => {
      // 如果type为all，返回list
      if (type === 'all') return true;
      // 如果type为active，返回未完成数据
      if (type === 'active') return !item.isDone;
      // 如果type为completed，返回已完成数据
      if (type === 'completed') return item.isDone;
    });

    // 7.1. 在App的render方法中，定义一个变量count，用来统计未完成的数量
    const count = list.filter((item) => !item.isDone).length;

    return (
      <section className="todoapp">
        {/* 头部 */}
        <Header handleAdd={this.handleAdd}></Header>
        {/*  2. 父传子技术，将list传给Main*/}
        {/* 5.2 通过父传子，将showList传给Main组件 */}
        <Main
          list={showList}
          handleUpdate={this.handleUpdate}
          handleDelete={this.handleDelete}
          handleCheckAll={this.handleCheckAll}
        ></Main>
        {/* 底部 */}
        {/* 4.2. 通过父传子，将type传给Footer */}
        {/*  2. 通过父传子，传count给Footer组件 */}
        <Footer
          count={count}
          type={type}
          handleToggle={this.handleToggle}
          handleClear={this.handleClear}
        ></Footer>
      </section>
    );
  }
}

class Header extends React.Component {
  // 1. Header声明一个state.task，
  state = {
    task: '',
  };
  handleChange = (e) => {
    this.setState({ task: e.target.value });
  };

  handleKeyUp = (e) => {
    // 完善-3. 如果数据为空，提示用户，且不添加数据
    if (!this.state.task.trim()) {
      alert('任务名不能为空');
      return;
    }

    if (e.keyCode === 13) {
      // 4. 通过子传父新增数据到list中
      this.props.handleAdd(this.state.task);
      // 完善-2. 新增后清除输入框内容
      this.setState({ task: '' });
    }
    // 完善-1 按esc，清除输入框内容
    if (e.keyCode === 27) {
      this.setState({ task: '' });
    }
  };

  // 2. Header成为受控组价：state.task绑定value，onChange监听value变化, setState更新state
  render() {
    return (
      <header className="header">
        <h1>todos</h1>
        <input
          className="new-todo"
          placeholder="需要做什么"
          autoFocus
          value={this.state.task}
          onChange={this.handleChange}
          /* 3. 使用onKeyUp监听回车事件，*/
          onKeyUp={this.handleKeyUp}
        />
      </header>
    );
  }
}

class Main extends React.Component {
  render() {
    const { list, handleUpdate, handleDelete, handleCheckAll } = this.props;

    // 10.1 通过计算list中，各任务的isDone属性，得到一个布尔值
    // 10.3 💥every需要注意，数据为空时，默认返回true
    const isAll = list.length ? list.every((item) => item.isDone) : false;

    return (
      <section className="main">
        {/*  10.2 将布尔值绑定给checked属性 */}
        {/*  11.1 使用onChange事件，获取到用户点击时，checked属性  */}
        <input
          onChange={(e) => handleCheckAll(e.target.checked)}
          checked={isAll}
          id="toggle-all"
          className="toggle-all"
          type="checkbox"
        />

        <label htmlFor="toggle-all">全选</label>
        <ul className="todo-list">
          {/*3. Main组件通过map，生成多个li，填入对应内容 */}
          {list.map((item) => (
            // 注意，给li加上key属性
            <li key={item.id} className={item.isDone ? 'completed' : ''}>
              <div className="view">
                {/* 2. 在 Main组件中，给多选按钮绑定一个onChange事件，通过 子传父技术 调用App中定义的方法 */}
                <input
                  className="toggle"
                  type="checkbox"
                  checked={item.isDone}
                  onChange={(e) => handleUpdate(e, item.id)}
                />
                <label>{item.task}</label>
                {/*2. 在Main中找到删除按钮，绑定onClick事件，通过子传父，调用handleDelete */}
                {/* 注意：💥 记得传id回去 */}
                <button className="destroy" onClick={() => handleDelete(item.id)}></button>
              </div>
            </li>
          ))}
        </ul>
      </section>
    );
  }
}

class Footer extends React.Component {
  render() {
    const { type, handleToggle, handleClear, count } = this.props;
    return (
      <footer className="footer">
        <span className="todo-count">
          {/* 7.3 Footer显示出props.count */}
          <strong>{count}</strong> 剩余
        </span>
        <ul className="filters">
          <li>
            {/* 4.3 在Footer中动态添加class */}
            {/* 4. 给按钮绑定onClick事件，通过子传父技术，修改App中的type */}
            <a
              onClick={() => handleToggle('all')}
              className={type === 'all' ? 'all selected' : 'all'}
              href="#/"
            >
              全部
            </a>
          </li>
          <li>
            <a
              onClick={() => handleToggle('active')}
              className={type === 'active' ? 'active selected' : 'active'}
              href="#/active"
            >
              未完成
            </a>
          </li>
          <li>
            <a
              onClick={() => handleToggle('completed')}
              className={type === 'completed' ? 'completed selected' : 'completed'}
              href="#/completed"
            >
              已完成
            </a>
          </li>
        </ul>
        {/* 2. 在Footer中给清除按钮，绑定一个onClick事件，通过子传父调用handleClear */}
        <button className="clear-completed" onClick={handleClear}>
          清除已完成
        </button>
      </footer>
    );
  }
}
